home *** CD-ROM | disk | FTP | other *** search
/ EuroCD 3 / EuroCD 3.iso / Emulators / v2600 / Source.lha / Source / tiasound.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-04-11  |  21.4 KB  |  600 lines

  1. /*****************************************************************************/
  2. /*                                                                           */
  3. /* Module:  TIA Chip Sound Simulator, V1.0                                   */
  4. /* Purpose: To emulate the sound generation hardware of the Atari TIA chip.  */
  5. /* Author:  Ron Fries                                                        */
  6. /* Date:    September 10, 1996                                               */
  7. /*                                                                           */
  8. /*****************************************************************************/
  9. /*                                                                           */
  10. /*                 License Information and Copyright Notice                  */
  11. /*                 ========================================                  */
  12. /*                                                                           */
  13. /* TiaSound is Copyright(c) 1996 by Ron Fries                                */
  14. /*                                                                           */
  15. /* This library is free software; you can redistribute it and/or modify it   */
  16. /* under the terms of version 2 of the GNU Library General Public License    */
  17. /* as published by the Free Software Foundation.                             */
  18. /*                                                                           */
  19. /* This library is distributed in the hope that it will be useful, but       */
  20. /* WITHOUT ANY WARRANTY; without even the implied warranty of                */
  21. /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library */
  22. /* General Public License for more details.                                  */
  23. /* To obtain a copy of the GNU Library General Public License, write to the  */
  24. /* Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.   */
  25. /*                                                                           */
  26. /* Any permitted reproduction of these routines, in whole or in part, must   */
  27. /* bear this legend.                                                         */
  28. /*                                                                           */
  29. /*****************************************************************************/
  30.  
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <time.h>
  34.  
  35.  
  36. /* define some data types to keep it platform independent */
  37. #define int8  char
  38. #define int16 short
  39. #define int32 int
  40.  
  41. #define uint8  unsigned int8 
  42. #define uint16 unsigned int16
  43. #define uint32 unsigned int32
  44.  
  45.  
  46. /* CONSTANT DEFINITIONS */
  47.  
  48. /* definitions for AUDCx (15, 16) */
  49. #define SET_TO_1     0x00      /* 0000 */
  50. #define POLY4        0x01      /* 0001 */
  51. #define DIV31_POLY4  0x02      /* 0010 */
  52. #define POLY5_POLY4  0x03      /* 0011 */
  53. #define PURE         0x04      /* 0100 */
  54. #define PURE2        0x05      /* 0101 */
  55. #define DIV31_PURE   0x06      /* 0110 */
  56. #define POLY5_2      0x07      /* 0111 */
  57. #define POLY9        0x08      /* 1000 */
  58. #define POLY5        0x09      /* 1001 */
  59. #define DIV31_POLY5  0x0a      /* 1010 */
  60. #define POLY5_POLY5  0x0b      /* 1011 */
  61. #define DIV3_PURE    0x0c      /* 1100 */
  62. #define DIV3_PURE2   0x0d      /* 1101 */
  63. #define DIV93_PURE   0x0e      /* 1110 */
  64. #define DIV3_POLY5   0x0f      /* 1111 */
  65.                  
  66. #define DIV3_MASK    0x0c                 
  67.                  
  68. #define AUDC0        0x15
  69. #define AUDC1        0x16
  70. #define AUDF0        0x17
  71. #define AUDF1        0x18
  72. #define AUDV0        0x19
  73. #define AUDV1        0x1a
  74.  
  75. /* the size (in entries) of the 4 polynomial tables */
  76. #define POLY4_SIZE  0x000f
  77. #define POLY5_SIZE  0x001f
  78. #define POLY9_SIZE  0x01ff
  79.  
  80. /* channel definitions */
  81. #define CHAN1       0
  82. #define CHAN2       1
  83.  
  84. #define FALSE       0
  85. #define TRUE        1
  86.  
  87.  
  88. /* LOCAL GLOBAL VARIABLE DEFINITIONS */
  89.  
  90. /* structures to hold the 6 tia sound control bytes */
  91. static uint8 AUDC[2];    /* AUDCx (15, 16) */
  92. static uint8 AUDF[2];    /* AUDFx (17, 18) */
  93. static uint8 AUDV[2];    /* AUDVx (19, 1A) */
  94.  
  95. static uint8 Outvol[2];  /* last output volume for each channel */
  96.  
  97.  
  98. /* Initialze the bit patterns for the polynomials. */
  99.  
  100. /* The 4bit and 5bit patterns are the identical ones used in the tia chip. */
  101. /* Though the patterns could be packed with 8 bits per byte, using only a */
  102. /* single bit per byte keeps the math simple, which is important for */
  103. /* efficient processing. */
  104.  
  105. static uint8 Bit4[POLY4_SIZE] =
  106.       { 1,1,0,1,1,1,0,0,0,0,1,0,1,0,0 };
  107.  
  108. static uint8 Bit5[POLY5_SIZE] =
  109.       { 0,0,1,0,1,1,0,0,1,1,1,1,1,0,0,0,1,1,0,1,1,1,0,1,0,1,0,0,0,0,1 };
  110.  
  111. /* I've treated the 'Div by 31' counter as another polynomial because of */
  112. /* the way it operates.  It does not have a 50% duty cycle, but instead */
  113. /* has a 13:18 ratio (of course, 13+18 = 31).  This could also be */
  114. /* implemented by using counters. */
  115.  
  116. static uint8 Div31[POLY5_SIZE] =
  117.       { 0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0 };
  118.  
  119. /* Rather than have a table with 511 entries, I use a random number */
  120. /* generator. */
  121.  
  122. static uint8 Bit9[POLY9_SIZE];
  123.  
  124. static uint8  P4[2]; /* Position pointer for the 4-bit POLY array */
  125. static uint8  P5[2]; /* Position pointer for the 5-bit POLY array */
  126. static uint16 P9[2]; /* Position pointer for the 9-bit POLY array */
  127.  
  128. static uint8 Div_n_cnt[2];  /* Divide by n counter. one for each channel */
  129. static uint8 Div_n_max[2];  /* Divide by n maximum, one for each channel */
  130.  
  131.  
  132. /* In my routines, I treat the sample output as another divide by N counter. */
  133. /* For better accuracy, the Samp_n_cnt has a fixed binary decimal point */
  134. /* which has 8 binary digits to the right of the decimal point. */
  135.  
  136. static uint16 Samp_n_max; /* Sample max, multiplied by 256 */
  137. static uint16 Samp_n_cnt; /* Sample cnt. */
  138.  
  139.  
  140.  
  141. /*****************************************************************************/
  142. /* Module:  Tia_sound_init()                                                 */
  143. /* Purpose: to handle the power-up initialization functions                  */
  144. /*          these functions should only be executed on a cold-restart        */
  145. /*                                                                           */
  146. /* Author:  Ron Fries                                                        */
  147. /* Date:    September 10, 1996                                               */
  148. /*                                                                           */
  149. /* Inputs:  sample_freq - the value for the '30 Khz' Tia audio clock         */
  150. /*          playback_freq - the playback frequency in samples per second     */
  151. /*                                                                           */
  152. /* Outputs: Adjusts local globals - no return value                          */
  153. /*                                                                           */
  154. /*****************************************************************************/
  155.  
  156. void Tia_sound_init (uint16 sample_freq, uint16 playback_freq)
  157. {
  158.    uint8 chan;
  159.    int16 n;
  160.  
  161.    /* fill the 9bit polynomial with random bits */
  162.    for (n=0; n<POLY9_SIZE; n++)
  163.    {
  164.       Bit9[n] = rand() & 0x01;       /* fill poly9 with random bits */
  165.    }
  166.  
  167.    /* calculate the sample 'divide by N' value based on the playback freq. */
  168.    Samp_n_max = (uint16)(((uint32)sample_freq<<8)/playback_freq);
  169.    Samp_n_cnt = 0;  /* initialize all bits of the sample counter */
  170.  
  171.    /* initialize the local globals */
  172.    for (chan = CHAN1; chan <= CHAN2; chan++)
  173.    {
  174.       Outvol[chan] = 0;
  175.       Div_n_cnt[chan] = 0;
  176.       Div_n_max[chan] = 0;
  177.       AUDC[chan] = 0;
  178.       AUDF[chan] = 0;
  179.       AUDV[chan] = 0;
  180.       P4[chan] = 0;
  181.       P5[chan] = 0;
  182.       P9[chan] = 0;
  183.    }
  184. }
  185.  
  186.  
  187. /*****************************************************************************/
  188. /* Module:  Update_tia_sound()                                               */
  189. /* Purpose: To process the latest control values stored in the AUDF, AUDC,   */
  190. /*          and AUDV registers.  It pre-calculates as much information as    */
  191. /*          possible for better performance.  This routine has not been      */
  192. /*          optimized.                                                       */
  193. /*                                                                           */
  194. /* Author:  Ron Fries                                                        */
  195. /* Date:    September 10, 1996                                               */
  196. /*                                                                           */
  197. /* Inputs:  addr - the address of the parameter to be changed                */
  198. /*          val - the new value to be placed in the specified address        */
  199. /*                                                                           */
  200. /* Outputs: Adjusts local globals - no return value                          */
  201. /*                                                                           */
  202. /*****************************************************************************/
  203.  
  204. void Update_tia_sound (uint16 addr, uint8 val)
  205. {
  206.     uint16 new_val = 0;
  207.     uint8 chan;
  208.  
  209.     /* determine which address was changed */
  210.     switch (addr)
  211.     {
  212.        case AUDC0:
  213.           AUDC[0] = val & 0x0f;
  214.           chan = 0;
  215.           break;
  216.  
  217.        case AUDC1:
  218.           AUDC[1] = val & 0x0f;
  219.           chan = 1;
  220.           break;
  221.  
  222.        case AUDF0:
  223.           AUDF[0] = val & 0x1f;
  224.           chan = 0;
  225.           break;
  226.  
  227.        case AUDF1:
  228.           AUDF[1] = val & 0x1f;
  229.           chan = 1;
  230.           break;
  231.  
  232.        case AUDV0:
  233.           AUDV[0] = (val & 0x0f) << 3;
  234.           chan = 0;
  235.           break;
  236.  
  237.        case AUDV1:
  238.           AUDV[1] = (val & 0x0f) << 3;
  239.           chan = 1;
  240.           break;
  241.  
  242.        default:
  243.           chan = 255;
  244.           break;
  245.     }
  246.  
  247.     /* if the output value changed */
  248.     if (chan != 255)
  249.     {
  250.        /* an AUDC value of 0 is a special case */
  251.        if (AUDC[chan] == SET_TO_1)
  252.        {
  253.           /* indicate the clock is zero so no processing will occur */
  254.           new_val = 0;
  255.  
  256.           /* and set the output to the selected volume */
  257.           Outvol[chan] = AUDV[chan];
  258.        }
  259.        else
  260.        {
  261.           /* otherwise calculate the 'divide by N' value */
  262.           new_val = AUDF[chan] + 1;
  263.  
  264.           /* if bits 2 & 3 are set, then multiply the 'div by n' count by 3 */
  265.           if ((AUDC[chan] & DIV3_MASK) == DIV3_MASK)
  266.           {
  267.              new_val *= 3;
  268.           }
  269.        }
  270.  
  271.        /* only reset those channels that have changed */
  272.        if (new_val != Div_n_max[chan])
  273.        {
  274.           /* reset the divide by n counters */
  275.           Div_n_max[chan] = new_val;
  276.           Div_n_cnt[chan] = new_val;
  277.  
  278.           /* reset the polynomial counters */
  279.           P4[chan] = 0;
  280.           P5[chan] = 0;
  281.           P9[chan] = 0;
  282.        }
  283.     }
  284. }
  285.  
  286.  
  287. /*****************************************************************************/
  288. /* Module:  Tia_process_2()                                                  */
  289. /* Purpose: To fill the output buffer with the sound output based on the     */
  290. /*          tia chip parameters.  This routine has not been optimized.       */
  291. /*          Though it is not used by the program, I've left it for reference.*/
  292. /*                                                                           */
  293. /* Author:  Ron Fries                                                        */
  294. /* Date:    September 10, 1996                                               */
  295. /*                                                                           */
  296. /* Inputs:  *buffer - pointer to the buffer where the audio output will      */
  297. /*                    be placed                                              */
  298. /*          n - size of the playback buffer                                  */
  299. /*                                                                           */
  300. /* Outputs: the buffer will be filled with n bytes of audio - no return val  */
  301. /*                                                                           */
  302. /*****************************************************************************/
  303.  
  304. void Tia_process_2 (register unsigned char *buffer, register uint16 n)
  305. {
  306.     register uint8 chan;
  307.  
  308.     /* loop until the buffer is filled */
  309.     while (n)
  310.     {
  311.        /* loop through the channels */
  312.        for (chan = CHAN1; chan <= CHAN2; chan++)
  313.        {
  314.           /* NOTE: this routine intentionally does not count down to zero */
  315.           /* since 0 is used as a special case - no clock */
  316.  
  317.           /* if the divide by N counter can count down */
  318.           if (Div_n_cnt[chan] > 1)
  319.           {
  320.              /* decrement and loop */
  321.              Div_n_cnt[chan]--;
  322.           }
  323.           /* otherwise if we've reached the bottom */
  324.           else if (Div_n_cnt[chan] == 1)
  325.           {
  326.              /* reset the counter */
  327.              Div_n_cnt[chan] = Div_n_max[chan];
  328.  
  329.              /* the P5 counter has multiple uses, so we inc it here */
  330.              P5[chan]++;
  331.              if (P5[chan] == POLY5_SIZE)
  332.                 P5[chan] = 0;
  333.  
  334.              /* check clock modifier for clock tick */
  335.  
  336.              /* if we're using pure tones OR
  337.                    we're using DIV31 and the DIV31 bit is set OR
  338.                    we're using POLY5 and the POLY5 bit is set */
  339.              if  (((AUDC[chan] & 0x02) == 0) ||
  340.                  (((AUDC[chan] & 0x01) == 0) && Div31[P5[chan]]) ||
  341.                  (((AUDC[chan] & 0x01) == 1) &&  Bit5[P5[chan]]))
  342.              {
  343.                 if (AUDC[chan] & 0x04)       /* pure modified clock selected */
  344.                 {
  345.                    if (Outvol[chan])         /* if the output was set */
  346.                       Outvol[chan] = 0;      /* turn it off */
  347.                    else
  348.                       Outvol[chan] = AUDV[chan];   /* else turn it on */
  349.                 }
  350.                 else if (AUDC[chan] & 0x08)  /* check for p5/p9 */
  351.                 {
  352.                    if (AUDC[chan] == POLY9)  /* check for poly9 */
  353.                    {
  354.                       /* inc the poly9 counter */
  355.                       P9[chan]++;
  356.                       if (P9[chan] == POLY9_SIZE)
  357.                          P9[chan] = 0;
  358.  
  359.                       if (Bit9[P9[chan]])    /* if poly9 bit is set */
  360.                          Outvol[chan] = AUDV[chan];
  361.                       else
  362.                          Outvol[chan] = 0;
  363.                    }
  364.                    else                      /* must be poly5 */
  365.                    {
  366.                       if (Bit5[P5[chan]])
  367.                          Outvol[chan] = AUDV[chan];
  368.                       else
  369.                          Outvol[chan] = 0;
  370.                    }
  371.                 }
  372.                 else  /* poly4 is the only remaining option */
  373.                 {
  374.                    /* inc the poly4 counter */
  375.                    P4[chan]++;
  376.                    if (P4[chan] == POLY4_SIZE)
  377.                       P4[chan] = 0;
  378.  
  379.                    if (Bit4[P4[chan]])
  380.                       Outvol[chan] = AUDV[chan];
  381.                    else
  382.                       Outvol[chan] = 0;
  383.                 }
  384.              }
  385.           }
  386.        }
  387.  
  388.        /* decrement the sample counter - value is 256 since the lower
  389.           byte contains the fractional part */
  390.        Samp_n_cnt -= 256;
  391.  
  392.        /* if the count down has reached zero */
  393.        if (Samp_n_cnt < 256)
  394.        {
  395.           /* adjust the sample counter */
  396.           Samp_n_cnt += Samp_n_max;
  397.  
  398.           /* calculate the latest output value and place in buffer */
  399.           *(buffer++) = Outvol[0] + Outvol[1];
  400.  
  401.           /* and indicate one less byte to process */
  402.           n--;
  403.        }
  404.     }
  405. }
  406.  
  407.  
  408. /*****************************************************************************/
  409. /* Module:  Tia_process()                                                    */
  410. /* Purpose: To fill the output buffer with the sound output based on the     */
  411. /*          tia chip parameters.  This routine has been optimized.           */
  412. /*                                                                           */
  413. /* Author:  Ron Fries                                                        */
  414. /* Date:    September 10, 1996                                               */
  415. /*                                                                           */
  416. /* Inputs:  *buffer - pointer to the buffer where the audio output will      */
  417. /*                    be placed                                              */
  418. /*          n - size of the playback buffer                                  */
  419. /*                                                                           */
  420. /* Outputs: the buffer will be filled with n bytes of audio - no return val  */
  421. /*                                                                           */
  422. /*****************************************************************************/
  423.  
  424. void Tia_process (register unsigned char *buffer, register uint16 n)
  425. {
  426.     register uint8 audc0,audv0,audc1,audv1;
  427.     register uint8 div_n_cnt0,div_n_cnt1;
  428.     register uint8 p5_0, p5_1,outvol_0,outvol_1;
  429.  
  430.     audc0 = AUDC[0];
  431.     audv0 = AUDV[0];
  432.     audc1 = AUDC[1];
  433.     audv1 = AUDV[1];
  434.  
  435.     /* make temporary local copy */
  436.     p5_0 = P5[0];
  437.     p5_1 = P5[1];
  438.     outvol_0 = Outvol[0];
  439.     outvol_1 = Outvol[1];
  440.     div_n_cnt0 = Div_n_cnt[0];
  441.     div_n_cnt1 = Div_n_cnt[1];
  442.  
  443.     /* loop until the buffer is filled */
  444.     while (n)
  445.     {
  446.        /* Process channel 0 */
  447.        if (div_n_cnt0 > 1)
  448.        {
  449.           div_n_cnt0--;
  450.        }
  451.        else if (div_n_cnt0 == 1)
  452.        {
  453.           div_n_cnt0 = Div_n_max[0];
  454.  
  455.           /* the P5 counter has multiple uses, so we inc it here */
  456.           p5_0++;
  457.           if (p5_0 == POLY5_SIZE)
  458.              p5_0 = 0;
  459.  
  460.           /* check clock modifier for clock tick */
  461.           if  (((audc0 & 0x02) == 0) ||
  462.               (((audc0 & 0x01) == 0) && Div31[p5_0]) ||
  463.               (((audc0 & 0x01) == 1) &&  Bit5[p5_0]))
  464.           {
  465.              if (audc0 & 0x04)       /* pure modified clock selected */
  466.              {
  467.                 if (outvol_0)        /* if the output was set */
  468.                    outvol_0 = 0;     /* turn it off */
  469.                 else
  470.                    outvol_0 = audv0; /* else turn it on */
  471.              }
  472.              else if (audc0 & 0x08)    /* check for p5/p9 */
  473.              {
  474.                 if (audc0 == POLY9)    /* check for poly9 */
  475.                 {
  476.                    /* inc the poly9 counter */
  477.                    P9[0]++;
  478.                    if (P9[0] == POLY9_SIZE)
  479.                       P9[0] = 0;
  480.  
  481.                    if (Bit9[P9[0]])
  482.                       outvol_0 = audv0;
  483.                    else
  484.                       outvol_0 = 0;
  485.                 }
  486.                 else                        /* must be poly5 */
  487.                 {
  488.                    if (Bit5[p5_0])
  489.                       outvol_0 = audv0;
  490.                    else
  491.                       outvol_0 = 0;
  492.                 }
  493.              }
  494.              else  /* poly4 is the only remaining option */
  495.              {
  496.                 /* inc the poly4 counter */
  497.                 P4[0]++;
  498.                 if (P4[0] == POLY4_SIZE)
  499.                    P4[0] = 0;
  500.  
  501.                 if (Bit4[P4[0]])
  502.                    outvol_0 = audv0;
  503.                 else
  504.                    outvol_0 = 0;
  505.              }
  506.           }
  507.        }
  508.  
  509.  
  510.        /* Process channel 1 */
  511.        if (div_n_cnt1 > 1)
  512.        {
  513.           div_n_cnt1--;
  514.        }
  515.        else if (div_n_cnt1 == 1)
  516.        {
  517.           div_n_cnt1 = Div_n_max[1];
  518.  
  519.           /* the P5 counter has multiple uses, so we inc it here */
  520.           p5_1++;
  521.           if (p5_1 == POLY5_SIZE)
  522.              p5_1 = 0;
  523.  
  524.           /* check clock modifier for clock tick */
  525.           if  (((audc1 & 0x02) == 0) ||
  526.               (((audc1 & 0x01) == 0) && Div31[p5_1]) ||
  527.               (((audc1 & 0x01) == 1) &&  Bit5[p5_1]))
  528.           {
  529.              if (audc1 & 0x04)       /* pure modified clock selected */
  530.              {
  531.                 if (outvol_1)        /* if the output was set */
  532.                    outvol_1 = 0;     /* turn it off */
  533.                 else
  534.                    outvol_1 = audv1; /* else turn it on */
  535.              }
  536.              else if (audc1 & 0x08)    /* check for p5/p9 */
  537.              {
  538.                 if (audc1 == POLY9)    /* check for poly9 */
  539.                 {
  540.                    /* inc the poly9 counter */
  541.                    P9[1]++;
  542.                    if (P9[1] == POLY9_SIZE)
  543.                       P9[1] = 0;
  544.  
  545.                    if (Bit9[P9[1]])
  546.                       outvol_1 = audv1;
  547.                    else
  548.                       outvol_1 = 0;
  549.                 }
  550.                 else                        /* must be poly5 */
  551.                 {
  552.                    if (Bit5[p5_1])
  553.                       outvol_1 = audv1;
  554.                    else
  555.                       outvol_1 = 0;
  556.                 }
  557.              }
  558.              else  /* poly4 is the only remaining option */
  559.              {
  560.                 /* inc the poly4 counter */
  561.                 P4[1]++;
  562.                 if (P4[1] == POLY4_SIZE)
  563.                    P4[1] = 0;
  564.  
  565.                 if (Bit4[P4[1]])
  566.                    outvol_1 = audv1;
  567.                 else
  568.                    outvol_1 = 0;
  569.              }
  570.           }
  571.        }
  572.  
  573.        /* decrement the sample counter - value is 256 since the lower
  574.           byte contains the fractional part */
  575.        Samp_n_cnt -= 256;
  576.  
  577.        /* if the count down has reached zero */
  578.        if (Samp_n_cnt < 256)
  579.        {
  580.           /* adjust the sample counter */
  581.           Samp_n_cnt += Samp_n_max;
  582.  
  583.           /* calculate the latest output value and place in buffer */
  584.           *(buffer++) = (outvol_0 + outvol_1)-64;
  585.  
  586.           /* and indicate one less byte to process */
  587.           n--;
  588.        }
  589.     }
  590.  
  591.     /* save for next round */
  592.     P5[0] = p5_0;
  593.     P5[1] = p5_1;
  594.     Outvol[0] = outvol_0;
  595.     Outvol[1] = outvol_1;
  596.     Div_n_cnt[0] = div_n_cnt0;
  597.     Div_n_cnt[1] = div_n_cnt1;
  598.  
  599. }
  600.